package com.sneakxy.cloudbase.platform.utils.web;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

public class HttpServletResponseUtils {

	public static final String HEADER_RANGE = "Range";
	
	public static final String HEADER_CONTENT_RANGE = "Content-Range";
	
	public static final String HEADER_CONTENT_LENGTH = "Content-Length";
	
	public static final String HEADER_ACCEPT_RANGES = "Accept-Ranges";
	
	public static final String HEADER_ACCEPT_UNIT = "bytes";
	
	public static void download(HttpServletRequest request, HttpServletResponse response, InputStream is, long fileLength) throws IOException {
		//分块下载
		RangeIndice indice = createRangeIndice(request, response, fileLength);
		try(OutputStream os = response.getOutputStream();
				BufferedInputStream input = new BufferedInputStream(is);) {
			for(RangeIndex index: indice.getIndice()) {
				if(is.markSupported()) {
					is.mark(0);
				}
				IOUtils.copyLarge(input, os, index.getStart(), index.length());
				if(is.markSupported()) {
					is.reset();
				}
			}
		}
	}
	
	/**
	 * 获得分块信息
	 * @param request
	 * @param response
	 * @param fileLength
	 * @return
	 */
	public static RangeIndice createRangeIndice(HttpServletRequest request, HttpServletResponse response, long fileLength) {
		String range = request.getHeader(HEADER_RANGE);
		//分块下载
		RangeIndice indice = RangeIndice.parseRangeIndice(range, fileLength);
		
		if(indice == null) {
			indice = new RangeIndice();
			indice.setLength(fileLength);
			indice.setIndice(new RangeIndex[] {new RangeIndex(0, fileLength)});
		} else {
			response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
		}
		response.setHeader(HEADER_ACCEPT_RANGES, HEADER_ACCEPT_UNIT);
		response.setHeader(HEADER_CONTENT_LENGTH, String.valueOf(indice.length()));
		response.setHeader(HEADER_CONTENT_RANGE, indice.toContentRangeHeader(fileLength));
		return indice;
	}
	
	private HttpServletResponseUtils() {}
	
	public static class RangeIndice {
		
		private long length;
		
		private RangeIndex[] indice;
		
		public static RangeIndice parseRangeIndice(String range, long totalLength) {
			if(StringUtils.isNotBlank(range) && !StringUtils.equals("null", range)) {
				range = StringUtils.split(range, "=")[1];
				String[] blocks = StringUtils.split(range, ",");
				RangeIndice result = new RangeIndice();
				RangeIndex[] indice = new RangeIndex[blocks.length];
				long length = 0;
				for(int i=0; i<blocks.length; i++) {
					indice[i] = RangeIndex.parseRangeIndex(StringUtils.trimToEmpty(blocks[i]), totalLength);
					length += indice[i].length();
				}
				result.indice = indice;
				result.length = length;
				return result;
			}
			return null;
		}

		public String toContentRangeHeader(long totalLength) {
			StringBuilder builder = new StringBuilder();
			builder.append(HEADER_ACCEPT_UNIT).append(" ");
			for(int i=0; i<indice.length; i++) {
				builder.append(indice[i].toContentRangeHeader());
				if(i + 1 < indice.length) {
					builder.append(",");
				}
			}
			builder.append("/").append(String.valueOf(totalLength));
			return builder.toString();
		}
		
		public long length() {
			return length;
		}

		public RangeIndex[] getIndice() {
			return indice;
		}
		
		protected void setLength(long length) {
			this.length = length;
		}
		
		protected void setIndice(RangeIndex[] indice) {
			this.indice = indice;
		}
		
	}
	
	public static class RangeIndex {
		
		private long start;
		
		private long end;
		
		private long length;
		
		public RangeIndex() {}
		
		public RangeIndex(long start, long length) {
			this.setStart(start);
			this.setLength(length);
		}
		
		public static RangeIndex parseRangeIndex(String range, long totalLength) {
			String[] array = StringUtils.splitByWholeSeparatorPreserveAllTokens(range, "-");
			RangeIndex index = new RangeIndex();
			long lastIndex = totalLength - 1;
			if(StringUtils.isBlank(array[0])) {
				//最后多少字节
				index.setStart(Math.min(totalLength - Long.parseLong(array[1]), lastIndex));
				index.setEnd(lastIndex);
			} else if(StringUtils.isBlank(array[1])) {
				//从第几个字节开始到结尾
				index.setStart(Math.min(Long.parseLong(array[0]), lastIndex));
				index.setEnd(lastIndex);
			} else {
				index.setStart(Long.parseLong(array[0]));
				index.setEnd(Math.min(lastIndex, Long.parseLong(array[1])));
			}
			index.setLength(index.getEnd() - index.getStart() + 1);
			return index;
		}

		public String toContentRangeHeader() {
			return StringUtils.join(String.valueOf(getStart()), "-", String.valueOf(getEnd()));
		}
		
		public long length() {
			return length;
		}
		
		public long getStart() {
			return start;
		}

		public long getEnd() {
			return end;
		}

		protected void setEnd(long end) {
			this.end = end;
		}

		protected void setStart(long start) {
			this.start = Math.max(start, 0);
		}
		
		protected void setLength(long length) {
			this.length = length;
		}

	}
	
}
